<template>
    <div id="map-dom"></div>
</template>

<script setup lang="ts">
import { onMounted, reactive } from "vue";
// 引入 leaflet 样式
import 'leaflet/dist/leaflet.css'
// 引入 leaflet js 文件 需要现在env.d.ts中主动声明
import L from "leaflet";

// 先声明leaflet里的一些对象类型，不然ts在后续赋值时会提示类型不对。
interface LeafletDom {
    // map对象
    mapDom: any,
    // 标注点
    marker: any,
    // 任意属性
    [propName: string]: any;
}

const data: LeafletDom = reactive({
    // map对象
    mapDom: null,
    // 标注点
    marker: null,
});

onMounted(() => {
    // 初始化地图 
    // 如果直接写在外面，因为setup相当于beforeCreate和created，所以会报错，获取不到map容器
    initMap();
})

// 初始化地图
const initMap = (): void => {
    // 获取map对象 参数：地理中心和缩放
    data.mapDom = L.map("map-dom").setView([30.508383, 114.393644], 16);
    // 设置底图
    L.tileLayer("http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
        // 此图层将显示的最大缩放级别（包括最大）
        maxZoom: 18,
        // 手机等高分辨率设备，图层显示可能会模糊，设置为true，可以改善。
        detectRetina: false,
    }).addTo(data.mapDom);

    // 比例尺 https://leafletjs.cn/reference-1.8.0.html#control-scale
    const scale = L.control
        .scale({
            // 控件的最大宽度，单位是像素
            maxWidth: 200,
            // 是否显示公制比例线（米/公里）
            metric: true,
            // 是否显示英制比例线（英里/英尺）
            imperial: false,
        })
        .addTo(data.mapDom);

    // 绘制圆形 参数：经纬度 + 选项对象
    const circle = drawCircle([30.508383, 114.393644], {
        // 描边颜色
        color: "red",
        // 填充颜色
        fillColor: "#f03",
        // 填充的不透明度
        fillOpacity: 0.5,
        // 圆的半径，以米为单位。
        radius: 100,
    });

    // 绘制多边形 参数 经纬度数组 + 选项对象 https://leafletjs.cn/reference-1.8.0.html#polyline-option
    const polygon = L.polygon([
        [30.512272, 114.393078],
        [30.512329, 114.393666],
        [30.511856, 114.393681],
        [30.511848, 114.39308],
    ], {
        // 描边颜色
        color: '#3388ff',
        // Stroke（描边）宽度，单位：像素
        weight: 3,
        // 填充颜色。默认为 color 选项的值
        fillColor: '#3388ff',
        // 填充的不透明度
        fillOpacity: 0.2,
    }).addTo(data.mapDom);


    // 建议监听提到openPopup前面，因为写到openPopup后面，会监听不到
    data.mapDom.on("popupopen", cleanPopupCloseBtnAttr);

    // 标注点 https://leafletjs.cn/reference-1.8.0.html#marker
    data.marker = L.marker([30.511027, 114.393467]);

    // 监听点击事件 onMapClick不能带参，比如我把data.mapDom传递下去，结果标注点会跟着地图缩放而移动，页面也会报错，
    // 我觉得大致原因是函数参数传递是值传递，map对象传递下去，可能会有问题。
    data.mapDom.on("click", onMapClick);

}

// 绘制圆形 参数：经纬度 + 选项对象 https://leafletjs.cn/reference-1.8.0.html#circle
const drawCircle = (latlng: any, options: object): any => {
    // 绘制圆形 并显示在地图上
    const circle = L.circle(latlng, options).addTo(data.mapDom);
    // 返回圆形对象
    return circle;
}

// 地图点击事件
const onMapClick = (e: any) => {
    // 从控件中移除给定的图层 移除之前的标注点
    data.mapDom.removeLayer(data.marker);
    // 在当前点击位置生成新的标注点
    data.marker = L.marker(e.latlng);
    // 在地图上显示标注点
    data.mapDom.addLayer(data.marker);
    // 给标注点添加弹窗并显示
    // 注意：默认的关闭按钮是a标签且自带href="#close",会自动跳转close页面
    // 1. 建议自定义关闭按钮
    // 2. 获取所有弹窗关闭按钮，并清除href属性
    data.marker.bindPopup(e.latlng.toString()).openPopup();
}

// 清除所有弹窗默认关闭按钮的href属性
const cleanPopupCloseBtnAttr = (): void => {
    // 获取所有弹窗关闭按钮
    const closeBtn: any = document.getElementsByClassName("leaflet-popup-close-button");
    // 遍历所有关闭按钮
    for (const iterator of closeBtn) {
        // 移除href
        iterator.removeAttribute("href");
    }
}

</script>

<style lang="less" scoped>
#map-dom {
    width: 100%;
    height: 100%;
}

.leaflet-container {
    font-size: 12px !important;
}
</style>